package com.example.filter;

import cn.hutool.json.JSONObject;
import com.example.common.HttpStatusEnum;
import com.example.mapper.UserMapper;
import com.example.pojo.User;
import com.example.util.JwtUtil;
import com.example.util.SpringGetBeanUtil;
import io.jsonwebtoken.Claims;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**判断是否登录的过滤器
 *
 * @email: pengyujun53@163.com
 * @author: peng_YuJun
 * @date: 2022/10/16
 * @time: 22:50
 */
@WebFilter
public class IsLoginFilter implements Filter {

    /**
     * 忽略拦截的名单
     */
    private String[] excludedUris;

    /**
     * 初始化
     * @param filterConfig
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //初始，获取忽略拦截的名单
        String param = filterConfig.getInitParameter("excludedUris");
        if (StringUtils.hasText(param)) {
            this.excludedUris = param.split(",");
        }
    }

    @Override
    public void destroy() {

    }

    /**
     * 具体做拦截的部分
     * @param servletRequest
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("application/json");


        //解决跨域
        if (request.getMethod().equals( RequestMethod.OPTIONS.toString())){
            return;
        }

        // 定义表示变量 并验证用户请求URI 是否包含不过滤路径
        boolean flag = false;
        if (excludedUris!=null)
            for (String uri:excludedUris) {
                if (request.getRequestURI().contains(uri)){
                    flag = true;
                    break;
                }
            }

        if(!flag){ //不在忽略拦截名单上，需要拦截
            // 验证请求路径是否存在 获取项目里的所有接口路径
            RequestMappingHandlerMapping requestMappingHandlerMapping = SpringGetBeanUtil.getBean(RequestMappingHandlerMapping.class);
            Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
            Set<String> apiEndpoints = new HashSet<>();
            for (RequestMappingInfo info : handlerMethods.keySet()) {
                Set<String> patterns = info.getPatternsCondition().getPatterns();
                apiEndpoints.addAll(patterns);
            }
            boolean isExitApi = apiEndpoints.stream().anyMatch(str -> {
                // 将 {任意参数名} 替换为正则表达式的通配符 (.*)，并对特殊字符进行转义
                String regexPattern = str.replaceAll("\\{[^}]*\\}", "(.*)");
                Pattern patt = Pattern.compile(regexPattern);
                Matcher matcher = patt.matcher(request.getServletPath());
                return matcher.matches();
            });
            if(!isExitApi){
                //TODO wanggc + 当找不到的的时候处理成错误页面
                //request.getRequestDispatcher("/error/index").forward(request,resp);
                //filterChain.doFilter(servletRequest, servletResponse);

                Map<String,Object> map = new HashMap<>();
                map.put("code", HttpStatusEnum.NOT_FOUND.getCode());
                map.put("msg",HttpStatusEnum.NOT_FOUND.getMessage());
                JSONObject json =  new JSONObject(map);
                PrintWriter writer = resp.getWriter();
                writer.print(json);
                writer.flush();
                writer.close();
                return;
            }
            // 验证访问身份
            String token = request.getHeader("Authorization"); //取出token
            Claims claims = JwtUtil.parsePayload(token);  //解析token
            if (claims != null){ //检验token
                Integer uid = Integer.parseInt((String) claims.get("uid"));
                UserMapper userMapper = SpringGetBeanUtil.getBean(UserMapper.class);
                User user = userMapper.selectById(uid);
                if (user!=null){ //token检验通过
                    filterChain.doFilter(servletRequest, servletResponse);
                }else { //若是请求用户不存在
                    Map<String,Object> map = new HashMap<>();
                    map.put("code", HttpStatusEnum.USER_NOT_EXIST.getCode());
                    map.put("msg",HttpStatusEnum.USER_NOT_EXIST.getMessage());
                    JSONObject json =  new JSONObject(map);
                    PrintWriter writer = resp.getWriter();
                    writer.print(json);
                    writer.flush();
                    writer.close();
                }
            }else { //若是token解析失败，解析失败的情况可能是token不是规范jwt，或者设置了过期时间并且jwt已过期
                Map<String,Object> map = new HashMap<>();
                map.put("code", HttpStatusEnum.LOGIN_EXPIRED.getCode());
                map.put("msg",HttpStatusEnum.LOGIN_EXPIRED.getMessage());
                JSONObject json =  new JSONObject(map);
                PrintWriter writer = resp.getWriter();
                writer.print(json);
                writer.flush();
                writer.close();
            }
        }else { //在忽略拦截名单上，不需要拦截
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }
}
